#include "object.h"

object::object(){}
vector<triangle> object::GetTriangleVector()
{
	return tri_vector;
}
vector<pt_vertex> object::GetVertexVector()
{
	return vtx_vector;
}

void object::AddTriangle(int vertex[3], int version_to_tri[3])
{
	int index = tri_vector.size();
	triangle newTriangle;

	newTriangle.alive = 1;
	newTriangle.index = index;
	for(int i=0; i<3; i++){
		newTriangle.pt[i] = vertex[i];
		newTriangle.version_to_tri[i] = version_to_tri[i];
	}
	newTriangle.child_tri.clear();

	tri_vector.push_back(newTriangle);
	cout<<"triangle "<<index<<" with vertex "<<vertex[0]<<","<<vertex[1]<<","<<vertex[2]
	<<" is added with versions="<<version_to_tri[0]<<","<<version_to_tri[1]<<","<<version_to_tri[2]<<endl;
}

//void object::AddTriangle(int vertex[3], int *ver0, int *ver1, int *ver2)
//{
//	triangle new_tri;
//	new_tri.index = tri_vector.size();
//	new_tri.alive = 1;
//	for(int i=0; i<3; i++) 
//		new_tri.pt[i] = vertex[i];
//	new_tri.version[0] = ver0;
//	new_tri.version[1] = ver1;
//	new_tri.version[2] = ver2;
//	new_tri.child_tri.clear();
//	tri_vector.push_back(new_tri);
//	cout<<"triangle "<<new_tri.index<<" with vertex "<<vertex[0]<<","<<vertex[1]<<","<<vertex[2]
//	<<" is added with versions="<<*new_tri.version[0]<<","<<*new_tri.version[1]<<","<<*new_tri.version[2]<<endl;
//}
void object::AddTriangle(triangle tri)
{
	tri_vector.push_back(tri);
}
triangle object::GetTriangleWithIndex(int index)
{
	return tri_vector[index];
}
void object::SetTriangleAsDeadWithIndex(int index)
{
	tri_vector[index].alive = false;
}
vector<triangle>::iterator object::GetTriangleVectorPointer()
{
	vector<triangle>::iterator iter = tri_vector.begin();
	return iter;
}
int object::AddVertex(Point v[3])
{
	// Check for duplicate vertex.
	vector<pt_vertex>::iterator iter = vtx_vector.begin();
	while( iter != vtx_vector.end()) {
		if(op.AlmostEqual2sComplement(iter->xyz[0],v[0],1) &&
			op.AlmostEqual2sComplement(iter->xyz[1],v[1],1) &&
			op.AlmostEqual2sComplement(iter->xyz[2],v[2],1))
			return iter->index;
		iter++;
		/*
		if( iter->xyz[0]==v[0] && iter->xyz[1]==v[1] && iter->xyz[2]==v[2])
			return iter->index;			// duplicate found. Return index of duplicate vertex.
		iter++;
		*/
	}
	// No duplicate, so add vertex.
	int index = vtx_vector.size();
	pt_vertex newVertex;
	newVertex.index = index;

	for(int i=0; i<3; i++)
		newVertex.xyz[i] = v[i];
	vtx_vector.push_back(newVertex);
	return index;
	//cout<<"Added vertex {"<<v[0]<<","<<v[1]<<","<<v[2]<<"} of index="<<index<<endl;
}
int object::AddVertexWithoutConstraint(Point v[3])
{
	int index = vtx_vector.size();
	pt_vertex newVertex;

	newVertex.index = index;
	for(int i=0; i<3; i++)
		newVertex.xyz[i] = v[i];
	vtx_vector.push_back(newVertex);
	return index;
}
int object::GetVertexSize()
{
	return vtx_vector.size();
}
void object::GetVertexPtArrayWithIndex(int vertex_index, Point point[3])
{
	op.SetPointEqualToPoint(vtx_vector[vertex_index].xyz, point);
}
void object::GetAllVertexPtArrayWithTriangleIndex(int tri_index, Point pt[3][3])
{
	triangle tri = GetTriangleWithIndex(tri_index);
	for(int i=0; i<3; i++)
		GetVertexPtArrayWithIndex(tri.pt[i], pt[i]);
}
int object::GetVertexIndexWithPtArray(Point pt[3])
{
	for(int i=0; i<vtx_vector.size(); i++) {
		/*
		if(vtx_vector[i].xyz[0]==pt[0] && vtx_vector[i].xyz[1]==pt[1] && vtx_vector[i].xyz[2]==pt[2])
			return vtx_vector[i].index;
			*/
		if( op.AlmostEqual2sComplement(vtx_vector[i].xyz[0],pt[0],1) &&
			op.AlmostEqual2sComplement(vtx_vector[i].xyz[1], pt[1],1) &&
			op.AlmostEqual2sComplement(vtx_vector[i].xyz[2], pt[2],1))
			return vtx_vector[i].index;
	}
	cout<<"Error! GetVertexIndexWithVertex() has no pt="<<pt[0]<<","<<pt[1]<<","<<pt[2]<<endl;
	return -1;
}
void object::AddChildTriangle(int parent_index, int child_index)
{
	tri_vector[parent_index].child_tri.push_back(child_index);
}
int object::GetTriangleSize()
{
	return tri_vector.size();
}
bool object::TriangleIndexHasVertexIndex(int tri_index, int vertex_index)
{
	for(int i=0; i<3; i++)
		if(tri_vector[tri_index].pt[i] == vertex_index)
			return true;
	return false;
}
bool object::TriangleIndexHasChildIndex(int tri_index, int child_index)
{
	triangle child_tri;
	triangle tri = GetTriangleWithIndex(tri_index);
	bool result_from_sub_child = false;
	if(tri.child_tri.empty())
		return tri_index==child_index;
	for(int i=0; i <tri.child_tri.size(); i++) {
		if( tri.child_tri[i] == child_index)
			return true;
		child_tri = GetTriangleWithIndex(tri.child_tri[i]);
		if(!child_tri.alive) {
			result_from_sub_child = TriangleIndexHasChildIndex(child_tri.index, child_index);
			if( result_from_sub_child == true)
				return true;
		}
	}
	return false;
}
//void object::SetTriangleIndexVersionValueAsPointer(int tri_index, int version_num, int *p)
//{
//	tri_vector[tri_index].version[version_num] = p;
//}
void object::SetTriangleIndexVersionValue(int tri_index,int version_num, int version_value)
{
	tri_vector[tri_index].version_to_tri[version_num] = version_value;
}

void object::UpdateTriangleVersionToTri(int tri_index, int version_index, int adj_tri_index)
{
	if( tri_index >= tri_vector.size() || tri_index < 0){
		cout<<"Error! In UpdateTriangleVersionToTri, no such tri_index="<<tri_index<<" found."<<endl;
		return;
	}
	tri_vector[tri_index].version_to_tri[version_index] = adj_tri_index;
}

int object::GetEdgeOfTriangle(triangle tri, int vertexref0, int vertexref1)
{
	for (int i=0; i<3; i++) {
		if ( tri.pt[i] == vertexref0 && tri.pt[(i+1)%3] == vertexref1 )
			return i;
		if ( tri.pt[i] == vertexref1 && tri.pt[(i+1)%3] == vertexref0 )
			return i;
	}
	return -1;	
}
// Function returns the edge of triangle that has vertexref as the starting
// point of the edge.
int object::GetEdgeOfTriangleThatHasVertexIndexAsStartingPointOfEdge(triangle tri, int vertexref)
{
	for(int i=0; i<3; i++)
		if( tri.pt[i] == vertexref)
			return i;
	return -1;
}
int object::FindChildTriThatHasPointInEdge(triangle parent_tri, float p[3], int &child_edge_type)
{
	// loop through each child triangle and find the triangle that has point p within its edge
	vector<int> child_indexes = parent_tri.child_tri;
	float pts[3][3];
	triangle child_tri;
	int subChildIndex = -1;

	for(int i=0; i<child_indexes.size(); i++) {
		child_tri = GetTriangleWithIndex(child_indexes[i]);
		
		if( !child_tri.alive ){
			subChildIndex = FindChildTriThatHasPointInEdge(child_tri, p, child_edge_type);
			if(subChildIndex != -1)
				return subChildIndex;
		}
		else {
			GetAllVertexPtArrayWithTriangleIndex(child_tri.index, pts);
			for(int j=0; j<3; j++)
				if(op.PointIsWithinTwoPoints(p, pts[j], pts[(j+1)%3])){
					child_edge_type = j;
					if( op.AreTwoPointsEqual(p, pts[j]) || op.AreTwoPointsEqual(p, pts[j+1]))
						child_edge_type = 4;
					return child_tri.index;
				}
		}
	}
	return -1;
}